<!-- components/ChatBox.vue -->
<template>
	<div ref="chatContent" class="chat-content" @scroll="onScroll">
		<div class="msg-row" :class="item.is_initiate ? 'msg-right' : ''" v-for="(item, index) in messages"
			:key="item.id || index">
			<!-- 左侧头像 -->
			<img v-if="!item.is_initiate" :src="item.reply_user?.avatar || DEFAULT_AVATAR"
				class="avatar avatar-right" />

			<!-- 消息气泡 -->
			<div class="msg-bubble" :class="item.is_initiate ? 'msg-right-bubble' : 'msg-left'">
				<div v-if="!item.content_img" class="msg-content">
					{{ item.content }}
				</div>
				<img v-else :src="item.content_img" class="msg-img" @load="scrollAfterRender(true)"
					@click="previewImage(item.content_img)" />
			</div>
		</div>

		<!-- 图片预览 -->
		<div v-if="previewVisible" class="preview-mask" @click="previewVisible = false">
			<img :src="previewUrl" class="preview-img" />
		</div>
	</div>
</template>

<script setup lang="ts">
	import { ref, watch, nextTick, onMounted, onBeforeUnmount, computed } from 'vue'
	import { useFetchApi } from '@/composables/useFetchApi'
	const { get } = useFetchApi()
	const { getToken } = useToken()

	const props = defineProps<{ sessionId : string }>()
	const DEFAULT_AVATAR = 'http://bet.dreammirac.com/static/2025-2-2/WechatIMG164.jpg'

	const messages = ref<any[]>([])
	const chatContent = ref<HTMLElement | null>(null)
	const previewVisible = ref(false)
	const previewUrl = ref('')
	const autoScroll = ref(true)

	let ws : WebSocket | null = null
	let reconnectAttempts = 0
	const maxReconnects = 5

	// ✅ 连接状态
	const connectionStatus = ref<'connecting' | 'open' | 'closed'>('connecting')

	// ✅ WebSocket 连接
	const connectWebSocket = () => {
		if (!props.sessionId) return
		ws = new WebSocket(`ws://api.flirtyzsex.com/api/ws/chat/${props.sessionId}`)
		connectionStatus.value = 'connecting'

		ws.onopen = () => {
			connectionStatus.value = 'open'
			reconnectAttempts = 0
		}

		ws.onmessage = async (e) => {
			let res
			try {
				res = JSON.parse(e.data)
			} catch (err) {
				return
			}

			const { action, data } = res

			// ✅ 初次加载历史消息
			if (action === 'init' && Array.isArray(data)) {
				messages.value = data
				await scrollAfterRender(true)
				return
			}

			// ✅ 新消息 push 一条
			if (action === 'new' && data?.list?.length) {
				messages.value.push(data.list[0])

				// 只在用户靠底部时滚动
				await scrollAfterRender()
				return
			}
		}

		ws.onclose = () => {
			connectionStatus.value = 'closed'
			reconnect()
		}
		ws.onerror = () => {
			connectionStatus.value = 'closed'
			reconnect()
		}
	}

	// ✅ 断线重连
	const reconnect = () => {
		if (reconnectAttempts >= maxReconnects) return
		reconnectAttempts++
		setTimeout(connectWebSocket, reconnectAttempts * 1000)
	}

	// ✅ 平滑滚动
	const scrollToBottom = () => {
		if (!chatContent.value) return
		chatContent.value.scrollTop = chatContent.value.scrollHeight
	}

	const scrollAfterRender = async (force = false) => {
		await nextTick()
		requestAnimationFrame(() => {
			if (force || autoScroll.value) scrollToBottom()
		})
	}

	// ✅ 监听滚动，判断是否停留底部
	const onScroll = () => {
		if (!chatContent.value) return
		const { scrollTop, clientHeight, scrollHeight } = chatContent.value
		autoScroll.value = scrollTop + clientHeight >= scrollHeight - 40
	}

	// ✅ 预览图片
	const previewImage = (url : string) => {
		previewUrl.value = url
		previewVisible.value = true
	}

	// ✅ 监听 sessionId 变化重新连接
	watch(() => props.sessionId, v => v && connectWebSocket())

	// ✅ 初始化
	onMounted(() => {
		if (props.sessionId) connectWebSocket()
		if (getToken()) get('/api/me_info')
	})

	// ✅ 销毁 websocket
	onBeforeUnmount(() => {
		ws?.close()
	})
</script>



<style scoped>
	.chat-content {
		flex: 1;
		overflow-y: auto;
		padding: 70px 10px 90px;
		box-sizing: border-box;
		background-color: #fff;
	}

	.msg-row {
		display: flex;
		align-items: flex-start;
		margin-bottom: 1.4rem;
	}

	.msg-right {
		justify-content: flex-end;
	}

	.avatar {
		width: 40px;
		height: 40px;
		border-radius: 50%;
	}

	.avatar-left {
		margin-left: 0.4rem;
	}

	.avatar-right {
		margin-right: 0.4rem;
	}

	.msg-bubble {
		max-width: 70%;
		padding: 0.6rem 0.8rem;
		border-radius: 4px;
		word-break: break-word;
		box-shadow: 0 1px 2px rgba(0, 0, 0, 0.08);
	}

	.msg-left {
		background: #f5f5f5;
	}

	.msg-right-bubble {
		background: #4d96e2;
		color: #fff;
	}

	.msg-content {
		font-size: 1.1rem;
	}

	.msg-img {
		max-width: 12rem;
		max-height: 12rem;
		border-radius: 8px;
		margin-top: 0.25rem;
		cursor: pointer;
	}

	.preview-mask {
		position: fixed;
		inset: 0;
		background: rgba(0, 0, 0, 0.9);
		display: flex;
		align-items: center;
		justify-content: center;
		z-index: 50;
	}

	.preview-img {
		max-width: 90%;
		max-height: 90%;
		border-radius: 8px;
	}
</style>